﻿using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Windows.Media;
using Styx;
using Styx.Common;
using Styx.CommonBot;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;

namespace TuanHAShadowPriest
{
    public partial class Classname
    {
        #region Attackable

        public bool Attackable(WoWUnit target)
        {
            if (ValidUnit(target) && target.DistanceSqr < 40*40 &&
                IsEnemy(target) && target.InLineOfSpellSight)
            {
                return true;
            }
            return false;
        }

        //prevent double ValidUnit Check
        public  bool AttackableValid(WoWUnit target)
        {
            if (target.DistanceSqr < 40*40 && IsEnemy(target) &&
                target.InLineOfSpellSight)
            {
                return true;
            }
            return false;
        }

        #endregion

        #region CastSpell
        public string LastCastSpell = "";
        public WoWUnit LastCastUnit;
        public DateTime LastCastTime = DateTime.Now;
        public DateTime LastUpdateMyLatency;

        public void CastSpell(string spellName, WoWUnit u)
        {
            if (u == null || !u.IsValid)
            {
                return;
            }

            SpellManager.Cast(spellName, u);

            //Prevent spamming
            if (LastCastUnit != u || spellName != LastCastSpell || LastCastTime + TimeSpan.FromMilliseconds(500) < Now)
            {
                string barTwo = "Mana: " + Math.Round(Me.ManaPercent);

                string unitName;
                if (u.IsPlayer)
                {
                    unitName = u.Class.ToString();
                }
                else
                {
                    unitName = u.Name;
                }
                Logging.Write(Colors.GreenYellow, DateTime.Now.ToString("ss:fff") + " - HP: " +
                                                  Math.Round(Me.HealthPercent) + "% - " +
                                                  barTwo + " - " +
                                                  unitName + " - " + Math.Round(u.Distance) + "y - " +
                                                  Math.Round(u.HealthPercent) + "% hp - " + spellName);
            }

            LastCastTime = DateTime.Now;
            LastCastSpell = spellName;
            LastCastUnit = u;

            TickMilisecond = DateTime.Now;

            if (!NoGCDSpells.Contains(spellName))
            {
                UpdateGCD();
            }

            if (LastUpdateMyLatency.AddMinutes(3) < DateTime.Now)
            {
                UpdateMyLatency();
                LastUpdateMyLatency = DateTime.Now;
            }
        }

        #endregion

        #region ConstantFace

        public void ConstantFace(WoWUnit unit)
        {
            if (!IsOverrideModeOn && !Me.IsSafelyFacing(unit))
            {
                WoWMovement.ConstantFace(unit.Guid);
            }
        }

        #endregion

        #region GCD

        public static DateTime GCDReady;

        //private void UpdateGCDEvent(object sender, LuaEventArgs raw)
        //{
        //    var args = raw.Args;
        //    var player = Convert.ToString(args[0]);

        //    // Not me ... Im out!
        //    if (player != "player")
        //    {
        //        return;
        //    }
        //    var spellID = Convert.ToInt32(args[4]);
        //    var spellName = WoWSpell.FromId(spellID).Name;

        //}

        public static void UpdateGCD()
        {
            GCDReady = DateTime.Now + SpellManager.Spells["Shadow Word: Pain"].CooldownTimeLeft;
        }

        public static bool GCDL()
        {
            return DateTime.Now + TimeSpan.FromMilliseconds(MyLatency) <= GCDReady;
        }

        public static bool Casting()
        {
            return Me.IsCasting && Me.CastingSpellId != 15407; //Mind Flay
        }

        public static bool CastingorGCDL()
        {
            return Casting() || GCDL();
        }

        #endregion

        #region GetAsyncKeyState

        [DllImport("user32.dll")]
        private static extern short GetAsyncKeyState(Keys vKey);

        #endregion

        #region CountEnemyNeary

        private double CountEnemyNeary(WoWObject unitCenter, float distance)
        {
            return
                NearbyUnFriendlyUnits.Where(
                    unit =>
                    unitCenter.Location.Distance(unit.Location) <= distance &&
                    unit.Combat && !unit.IsPet &&
                    (unit.IsTargetingMyPartyMember || unit.IsTargetingMyRaidMember ||
                     unit.IsTargetingMeOrPet)).Aggregate
                    <WoWUnit, double>(0, (current, unit) => current + 1);
        }

        #endregion

        #region CountEnemyFromPoint

        //private double CountEnemyFromPoint(WoWPoint pointCenter, float radius)
        //{
        //    return
        //        NearbyUnFriendlyUnits.Where(
        //            unit =>
        //            pointCenter.Distance(unit.Location) <= radius &&
        //            unit.Combat).Aggregate
        //            <WoWUnit, double>(0, (current, unit) => current + 1);
        //}

        #endregion

        #region GetAllMyAuras

        public DateTime LastGetAllMyAuras = DateTime.Now;

        public void DumpAuras()
        {
            if (LastGetAllMyAuras.AddSeconds(10) < DateTime.Now)
            {
                var i = 1;
                Logging.Write(LogLevel.Diagnostic, "----------------------------------");
                foreach (var aura in Me.GetAllAuras())
                {
                    Logging.Write(LogLevel.Diagnostic,
                                  i + ". Me.GetAllAuras Name: " + aura.Name + " - SpellId: " + aura.SpellId);
                    i = i + 1;
                }
                Logging.Write(LogLevel.Diagnostic, "----------------------------------");

                i = 1;
                Logging.Write(LogLevel.Diagnostic, "----------------------------------");
                foreach (var aura in Me.Auras)
                {
                    Logging.Write(LogLevel.Diagnostic,
                                  i + ". Me.Auras - Name: " + aura.Value.Name + " - SpellId: " + aura.Value.SpellId);
                    i = i + 1;
                }
                Logging.Write(LogLevel.Diagnostic, "----------------------------------");

                i = 1;
                Logging.Write(LogLevel.Diagnostic, "----------------------------------");
                foreach (var aura in Me.ActiveAuras)
                {
                    Logging.Write(LogLevel.Diagnostic,
                                  i + ". Me.ActiveAuras - Name: " + aura.Value.Name + " - SpellId: " +
                                  aura.Value.SpellId);
                    i = i + 1;
                }
                Logging.Write(LogLevel.Diagnostic, "----------------------------------");

                i = 1;
                Logging.Write(LogLevel.Diagnostic, "----------------------------------");
                foreach (var aura in Me.PassiveAuras)
                {
                    Logging.Write(LogLevel.Diagnostic,
                                  i + ". Me.PassiveAuras - Name: " + aura.Value.Name + " - SpellId: " +
                                  aura.Value.SpellId);
                    i = i + 1;
                }
                Logging.Write(LogLevel.Diagnostic, "----------------------------------");

                LastGetAllMyAuras = DateTime.Now;
            }
        }

        #endregion

        #region GetUnitHaloSafe;

        public WoWUnit UnitHaloSafe;

        private bool IsHaloSafe()
        {
            UnitHaloSafe = null;
            UnitHaloSafe = (from unit in NearbyUnFriendlyUnits
                            //where Me.CurrentMap.IsDungeon || Me.CurrentMap.IsRaid
                            where !unit.Combat ||
                                  Me.CurrentMap.IsDungeon && !unit.IsTargetingMyPartyMember ||
                                  Me.CurrentMap.IsRaid && !unit.IsTargetingMyRaidMember
                            where unit.DistanceSqr < 33*33
                            select unit).FirstOrDefault();
            return UnitHaloSafe == null;
        }

        #endregion

        #region GetUnitSWP

        public WoWUnit UnitSWP;

        private bool GetUnitSWP()
        {
            UnitSWP = null;
            UnitSWP = (from unit in NearbyUnFriendlyUnits
                       where !Blacklist.Contains(unit.Guid)
                       where Me.Combat && unit.Combat
                       //Make sure dont aggro extra group
                       where
                           (Me.CurrentMap.IsDungeon && unit.IsTargetingMyPartyMember ||
                            Me.CurrentMap.IsRaid && unit.IsTargetingMyRaidMember)
                       where unit.ThreatInfo.RawPercent < 100
                       where MyAuraTimeLeft("Shadow Word: Pain", unit) < 3000
                       where unit.InLineOfSpellSight
                       select unit).FirstOrDefault();
            return UnitSWP != null;
        }

        #endregion

        #region GetUnitMindSear

        public WoWUnit UnitMindSear;

        private bool GetUnitMindSear()
        {
            UnitMindSear = null;
            UnitMindSear = (from unit in NearbyUnFriendlyUnits
                            where !Blacklist.Contains(unit.Guid)
                            where Me.Combat
                            where Me.CurrentMap.IsDungeon || Me.CurrentMap.IsRaid
                            where unit.Combat
                            where !unit.IsFlying
                            where !unit.IsFalling
                            //Make sure dont aggro extra group
                            where (unit.IsTargetingMyPartyMember || unit.IsTargetingMyRaidMember)
                            //where !unit.IsTargetingMeOrPet
                            where unit.ThreatInfo.RawPercent < 100
                            where CountEnemyNeary(unit, 10) > 3
                            orderby CountEnemyNeary(unit, 10) descending
                            where unit.InLineOfSpellSight
                            select unit).FirstOrDefault();
            return UnitMindSear != null;
        }

        #endregion

        #region GetUnitLowThreat

        public WoWUnit UnitLowThreat;

        #endregion

        #region IndexToKeys

        public Keys KeyTwo;

        public Keys IndexToKeys(int index)
        {
            switch (index)
            {
                case 1:
                    return Keys.A;
                case 2:
                    return Keys.B;
                case 3:
                    return Keys.C;
                case 4:
                    return Keys.D;
                case 5:
                    return Keys.E;
                case 6:
                    return Keys.F;
                case 7:
                    return Keys.G;
                case 8:
                    return Keys.H;
                case 9:
                    return Keys.I;
                case 10:
                    return Keys.I;
                case 11:
                    return Keys.K;
                case 12:
                    return Keys.L;
                case 13:
                    return Keys.M;
                case 14:
                    return Keys.N;
                case 15:
                    return Keys.O;
                case 16:
                    return Keys.P;
                case 17:
                    return Keys.Q;
                case 18:
                    return Keys.R;
                case 19:
                    return Keys.S;
                case 20:
                    return Keys.T;
                case 21:
                    return Keys.U;
                case 22:
                    return Keys.V;
                case 23:
                    return Keys.W;
                case 24:
                    return Keys.X;
                case 25:
                    return Keys.Y;
                case 26:
                    return Keys.Z;
                case 27:
                    return Keys.Up;
                case 28:
                    return Keys.Down;
                case 29:
                    return Keys.Left;
                case 30:
                    return Keys.Right;
            }
            return Keys.None;
        }

        #endregion

        #region IsHealing

        //private static bool IsHealing()
        //{
        //    return Me.IsCasting &&
        //           (Me.CastingSpell.Name == "Flash of Light" || Me.CastingSpell.Name == "Divine Light" ||
        //            Me.CastingSpell.Name == "Holy Light" || Me.CastingSpell.Name == "Holy Radiance");
        //}

        #endregion

        #region IsAttacking

        //private static bool IsAttacking()
        //{
        //    return Me.IsCasting && Me.CastingSpell.Name == "Denounce";
        //}

        #endregion

        #region IsEnemy

        //public ulong RealGuid;

        //private static WoWPlayer GetUnitIsInMyPartyOrRaid(WoWUnit u)
        //{
        //    using (StyxWoW.Memory.AcquireFrame())
        //    {
        //        return (from unit in ObjectManager.GetObjectsOfType<WoWPlayer>(true, true)
        //                where unit.IsInMyPartyOrRaid
        //                //|| unit.IsMe && (!Me.IsInParty || !Me.IsInRaid)
        //                where unit.Guid == u.Guid || unit.Guid == u.CreatedByUnitGuid
        //                select unit).FirstOrDefault();
        //    }
        //}


        public bool IsEnemy(WoWUnit target)
        {
            if (target == null)
            {
                return false;
            }

            if (!target.IsFriendly || target.Name.Contains("Dummy") && target.IsWithinMeleeRange)
            {
                return true;
            }
            return false;
        }

        public bool IsMyPartyRaidMember(WoWUnit u)
        {
            if (u == null || !u.IsValid)
            {
                return false;
            }

            if (u.IsPet || u.IsTotem)
            {
                if (Me.PartyMembers.Contains(u.CreatedByUnit) || Me.RaidMembers.Contains(u.CreatedByUnit))
                {
                    return true;
                }
            }
            else if (u.IsPlayer)
            {
                if (Me.PartyMembers.Contains(u) || Me.RaidMembers.Contains(u))
                {
                    return true;
                }
            }

            return false;
        }

        #endregion

        #region IsMeorFocus

        public bool IsMeorFocus(WoWUnit target)
        {
            if (target == Me ||
                target == Me.FocusedUnit && ValidUnit(Me.FocusedUnit) && !IsEnemy(Me.FocusedUnit) ||
                target == Me.CurrentTarget && ValidUnit(Me.CurrentTarget) && !IsEnemy(Me.CurrentTarget) ||
                Me.CurrentMap.IsArena)
            {
                return true;
            }
            return false;
        }

        #endregion

        #region MeIsTank

        public static bool MeIsTank
        {
            get
            {
                //return (StyxWoW.Me.Role & WoWPartyMember.GroupRole.Tank) != 0 ||
                //        Tanks.All(t => !t.IsAlive) && StyxWoW.Me.HasAura("Bear Form");
                return (StyxWoW.Me.Role & WoWPartyMember.GroupRole.Tank) != 0;
            }
        }

        #endregion

        #region MyAura

        public bool MyAura(string auraName, WoWUnit u)
        {
            using (StyxWoW.Memory.AcquireFrame())
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return false;

                bool aura = u.GetAllAuras().Any(a => a.Name == auraName && a.CreatorGuid == Me.Guid);

                return aura;
                //return u.ActiveAuras.Any(a => a.Value.Name == auraName && a.Value.CreatorGuid == Me.Guid);
            }
        }


        public bool MyAura(int auraID, WoWUnit u)
        {
            using (StyxWoW.Memory.AcquireFrame())
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return false;

                bool aura = u.GetAllAuras().Any(a => a.SpellId == auraID && a.CreatorGuid == Me.Guid);

                return aura;

                //return u.ActiveAuras.Any(a => a.Value.SpellId == auraID && a.Value.CreatorGuid == Me.Guid);
            }
        }

        #endregion

        #region MyAuraTimeLeft

        public double MyAuraTimeLeft(string auraName, WoWUnit u)
        {
            using (StyxWoW.Memory.AcquireFrame())
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return 0;

                WoWAura aura = u.GetAllAuras().FirstOrDefault(a => a.Name == auraName && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
        }

        public double MyAuraTimeLeft(int auraID, WoWUnit u)
        {
            using (StyxWoW.Memory.AcquireFrame())
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return 0;

                WoWAura aura = u.GetAllAuras().FirstOrDefault(a => a.SpellId == auraID && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
        }

        #endregion

        #region UnitAuraTimeLeft

        public double UnitAuraTimeLeft(string auraName, WoWUnit u)
        {
            using (StyxWoW.Memory.AcquireFrame())
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return 0;

                WoWAura aura = u.GetAllAuras().FirstOrDefault(a => a.Name == auraName && a.CreatorGuid == u.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
        }

        public double UnitAuraTimeLeft(int auraID, WoWUnit u)
        {
            using (StyxWoW.Memory.AcquireFrame())
            {
                if (u == null)
                    return 0;

                WoWAura aura = u.GetAllAuras().FirstOrDefault(a => a.SpellId == auraID && a.CreatorGuid == u.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
        }

        #endregion

        #region MyAuraStackCount

        public double MyAuraStackCount(string auraName, WoWUnit u)
        {
            using (StyxWoW.Memory.AcquireFrame())
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return 0;

                WoWAura aura = u.GetAllAuras().FirstOrDefault(a => a.Name == auraName && a.CreatorGuid == u.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
        }

        public double MyAuraStackCount(int auraID, WoWUnit u)
        {
            using (StyxWoW.Memory.AcquireFrame())
            {
                if (u == null || !u.IsValid || !u.IsAlive)
                    return 0;

                WoWAura aura = u.GetAllAuras().FirstOrDefault(a => a.SpellId == auraID && a.CreatorGuid == u.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
        }

        #endregion

        #region TalentSort

        public byte TalentSort(WoWUnit target)
        {
            if (target == null)
            {
                return 0;
            }

            if (target.Class == WoWClass.DeathKnight)
            {
                return 1;
            }

            if (target.Class == WoWClass.Druid)
            {
                if (target.Buffs.ContainsKey("Moonkin Form"))
                    return 3;
                if ((target.Buffs.ContainsKey("Leader of the Pack") &&
                     target.Buffs["Leader of the Pack"].CreatorGuid == target.Guid) || target.MaxMana < 40000)
                    return 1;
                return 4;
            }

            if (target.Class == WoWClass.Hunter)
            {
                return 2;
            }

            if (target.Class == WoWClass.Mage)
            {
                return 3;
            }

            if (target.Class == WoWClass.Paladin)
            {
                if (target.MaxMana >= 80000)
                    return 4;
                return 1;
            }

            if (target.Class == WoWClass.Priest)
            {
                if (target.HasAura("Shadowform"))
                    return 3;
                return 4;
            }

            if (target.Class == WoWClass.Rogue)
            {
                return 1;
            }

            if (target.Class == WoWClass.Shaman)
            {
                if (target.MaxMana < 40000)
                    return 1;
                if (target.Buffs.ContainsKey("Elemental Oath") &&
                    target.Buffs["Elemental Oath"].CreatorGuid == target.Guid)
                    return 3;
                return 4;
            }

            if (target.Class == WoWClass.Warlock)
            {
                return 3;
            }

            if (target.Class == WoWClass.Warrior)
            {
                return 1;
            }

            return 0;
        }

        public byte TalentSortSimple(WoWUnit target)
        {
            byte sortSimple = TalentSort(target);

            if (sortSimple == 4)
            {
                return 4;
            }

            if (sortSimple < 4 && sortSimple > 0)
            {
                return 1;
            }

            return 0;
        }

        #endregion

        #region UpdateMyLatency

        public static double MyLatency;

        public void UpdateMyLatency()
        {
            //If SLagTolerance enabled, start casting next spell MyLatency Millisecond before GlobalCooldown ready.

            MyLatency = (StyxWoW.WoWClient.Latency);

            //Use here because Lag Tolerance cap at 400
            //Logging.Write("----------------------------------");
            //Logging.Write("MyLatency: " + MyLatency);
            //Logging.Write("----------------------------------");

            if (MyLatency > 400)
            {
                //Lag Tolerance cap at 400
                MyLatency = 400;
            }
        }

        #endregion

        #region UpdateMyTalent

        public static string HasTalent = "";

        public void UpdateMyTalentEvent(object sender, LuaEventArgs args)
        {
            UpdateMyTalent();
        }

        public void UpdateMyTalent()
        {
            HasTalent = "";
            for (int i = 1; i <= 18; i++)
            {
                HasTalent = HasTalent +
                            Lua.GetReturnVal<String>(
                                string.Format(
                                    "local t= select(5,GetTalentInfo({0})) if t == true then return '['..select(1,GetTalentInfo({0}))..'] ' end return nil",
                                    i), 0);
            }

            Logging.Write("----------------------------------");
            Logging.Write("Talent:");
            Logging.Write(HasTalent);
            Logging.Write("----------------------------------");
        }

        #endregion

        #region UpdateMyGlyph

        // [Glyph of Beacon of Light] [Glyph of Harsh Words]
        public static string HasGlyph = "";

        public static string NoGCDSpells =
            "[Fortifying Brew] [Spear Hand Strike] [Invoke Xuen, the White Tiger] [Roll] [Clash] [Provoke] [Leer of the Ox] [Purifying Brew] [Elusive Brew] [Tigereye Brew] [Energizing Brew] [Chi Torpedo] [Energy Brew] [Zen Meditation]";


        public void UpdateMyGlyphEvent(object sender, LuaEventArgs args)
        {
            UpdateMyGlyph();
        }

        public void UpdateMyGlyph()
        {
            HasGlyph = "";
            var glyphCount = Lua.GetReturnVal<int>("return GetNumGlyphSockets()", 0);

            if (glyphCount != 0)
            {
                for (int i = 1; i <= glyphCount; i++)
                {
                    string lua =
                        String.Format(
                            "local enabled, glyphType, glyphTooltipIndex, glyphSpellID, icon = GetGlyphSocketInfo({0});if (enabled) then return glyphSpellID else return 0 end",
                            i);

                    var glyphSpellId = Lua.GetReturnVal<int>(lua, 0);

                    try
                    {
                        if (glyphSpellId > 0)
                        {
                            HasGlyph = HasGlyph + "[" + (WoWSpell.FromId(glyphSpellId)) + "] ";
                        }
                        else
                        {
                            Logging.Write("Glyphdetection - No Glyph in slot " + i);
                            //TreeRoot.Stop();
                        }
                    }
                    catch (Exception ex)
                    {
                        Logging.Write("We couldn't detect your Glyphs");
                        Logging.Write("Report this message to us: " + ex);
                        //TreeRoot.Stop();
                    }
                }
            }

            Logging.Write("----------------------------------");
            Logging.Write("Glyph:");
            Logging.Write(HasGlyph);
            Logging.Write("----------------------------------");
        }

        #endregion

        #region ValidUnit

        public bool ValidUnit(WoWUnit u)
        {
            if (u == null || !u.IsValid || !u.Attackable || !u.IsAlive || !u.CanSelect ||
                u.IsCritter && (u.CurrentTarget == null || u.CurrentTarget != null && u.CurrentTarget != Me) ||
                u.IsNonCombatPet || Blacklist.Contains(u.Guid))
            {
                return false;
            }
            return true;
        }

        #endregion
    }
}